/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.ipti.br.tag.dao;

import org.ipti.br.tag.entity.*;
import java.io.Serializable;
import java.util.Calendar;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

/**
 *
 * @author ipti
 */
@Stateless
public class WorkFacade extends AbstractFacade<Work> implements Serializable {

    @PersistenceContext(unitName = "TAG2PU")
    private EntityManager em;

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    public WorkFacade() {
        super(Work.class);
    }

    @Override
    public void create(Work work) {
        getEntityManager().persist(work);
    }

    @Override
    public void edit(Work work) {
        getEntityManager().merge(work);
    }

    public void editForSynchronization(Work work) {
        getEntityManager().merge(work);
    }
    
    public Work getRoot(WorkTopic topic) {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Work> cq = cb.createQuery(Work.class);
        Root<Work> rt = cq.from(Work.class);
        
        cq.where(cb.equal(rt.get(Work_.topic).get(WorkTopic_.id), topic.getId()));
        
        try {
            return getEntityManager().createQuery(cq).getSingleResult();
        } catch (NoResultException nre) {
            return null;
        }
    }
    
    public List<Work> list(Calendar year,Discipline discipline, Organization org) {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Work> cq = cb.createQuery(Work.class);
        Root<Work> rt = cq.from(Work.class);
        
        Predicate p1 = cb.equal(rt.get(Work_.discipline).get(Discipline_.id), discipline.getId());
        Predicate p2 = cb.equal(rt.get(Work_.organization).get(Organization_.id), org.getId());
        Predicate p3 = cb.lessThan(rt.get(Work_.topic).get(WorkTopic_.initialDate), year);
        Predicate p4 = cb.greaterThan(rt.get(Work_.topic).get(WorkTopic_.finalDate), year);
        Predicate p5 = cb.isNull(rt.get(Work_.topic).get(WorkTopic_.finalDate));
        cq.where(cb.and(p1, p2, p3, cb.or(p4, p5)));

        return getEntityManager().createQuery(cq).getResultList();
    }
    
    public List<WorkTopic> list(Organization org){
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<WorkTopic> cq = cb.createQuery(WorkTopic.class);
        Root<Work> rt = cq.from(Work.class);
        Join<Work,WorkTopic> topic = rt.join(Work_.topic);
        cq.select(rt.get(Work_.topic));
        
        Predicate p = cb.equal(rt.get(Work_.organization).get(Organization_.id),org.getId()); //aqui é mais embaixo| apenas o topic root é apontado por work
        Predicate p1 = cb.isNull(topic.get(WorkTopic_.finalDate));
        cq.where(cb.and(p,p1));
//        cq.orderBy(cb.asc(rt.get(Work_.discipline).get(Discipline_.id)),cb.asc(topic.get(WorkTopic_.father).get(WorkTopic_.id)));
        
        return getEntityManager().createQuery(cq).getResultList();
    }
    
    public List<Integer> rootCodes(Organization org, Discipline discipline){
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Integer> cq = cb.createQuery(Integer.class);
        Root<Work> rt = cq.from(Work.class);
        Join<Work,WorkTopic> topic = rt.join(Work_.topic);
        cq.select(topic.get(WorkTopic_.code));
        
        Predicate p = cb.equal(rt.get(Work_.organization).get(Organization_.id),org.getId());
        Predicate p1 = cb.equal(rt.get(Work_.discipline).get(Discipline_.id),org.getId());
        Predicate p2 = cb.or(cb.isNull(topic.get(WorkTopic_.finalDate)),cb.greaterThanOrEqualTo(topic.get(WorkTopic_.finalDate), Calendar.getInstance()));
        cq.where(p,p1,p2);
        cq.orderBy(cb.asc(topic.get(WorkTopic_.code)));
        
        return getEntityManager().createQuery(cq).getResultList();
    }

    public List<Work> modifiedWorks(Calendar initialDate, Calendar finalDate, Long serialNumber) {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Work> cq = cb.createQuery(Work.class);
        Root<Work> from = cq.from(Work.class);
        Predicate predicate1 = cb.notEqual(from.get(Work_.serialNumber), serialNumber);
        Predicate predicate2 = cb.greaterThanOrEqualTo(from.get(Work_.lastModified), initialDate);
        Predicate predicate3 = cb.lessThan(from.get(Work_.lastModified), finalDate);
        cq.where(cb.and(predicate1, predicate2, predicate3));

        return getEntityManager().createQuery(cq).getResultList();
    }
}
